package ru.ipo.dces.plugins.admin;

import com.l2fprod.common.swing.JDirectoryChooser;
import info.clearthought.layout.TableLayout;
import ru.ipo.dces.client.Controller;
import ru.ipo.dces.client.Localization;
import ru.ipo.dces.client.Settings;
import ru.ipo.dces.clientservercommunication.AvailablePluginsResponse;
import ru.ipo.dces.clientservercommunication.DownloadPluginResponse;
import ru.ipo.dces.clientservercommunication.PluginSide;
import ru.ipo.dces.pluginapi.Plugin;
import ru.ipo.dces.pluginapi.PluginEnvironment;
import ru.ipo.dces.plugins.admin.beans.PluginState;
import ru.ipo.dces.plugins.admin.components.PluginsTable;
import ru.ipo.dces.plugins.admin.resources.ImageResources;
import ru.ipo.dces.server.ServerFailReason;
import ru.ipo.dces.utils.FileSystemUtils;
import ru.ipo.dces.utils.ResponseHandler;

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static java.awt.event.KeyEvent.VK_ENTER;

public class PluginsManagementPluginV2 extends JPanel implements Plugin {

    private final List<String> pluginsOnServer = new ArrayList<String>();
    private static final int separatorGap = 5;
    private static final int verticalGap = 10;
    private File updateFolder = null;
    private File downloadFolder = null;
    private PluginsTable pluginsTable;
    private JButton refresh = new JButton("Обновить");
    private JTextField downloadDirectory = new JTextField();
    private JTextField updateDirectory = new JTextField();
    private String downloadDirectoryPath = Settings.getInstance().getPluginsDirectory();
    private String uploadDirectoryPath = Settings.getInstance().getPluginsUpdateDirectory();
    private JButton chooseDownloadDirectory = new JButton("Выбрать");
    private JButton chooseUploadDirectory = new JButton("Выбрать");
    private JButton downloadFromServer = new JButton("Скачать с сервера");
    private JButton uploadToServer = new JButton("Загрузить на сервер");
    private JButton delete = new JButton("Удалить");
    public PluginsStates pluginsStates = new PluginsStates();

    public PluginsManagementPluginV2(PluginEnvironment env) {
        env.setTitle(Localization.getAdminPluginName(PluginsManagementPluginV2.class));
        setupUI();
        setListeners();
    }

    @Override
    public JPanel getPanel() {
        return this;
    }

    @Override
    public void activate() {
        resetState();
        updatePluginsStates();
    }

    @Override
    public void deactivate() {
    }

    private void setupUI() {
        pluginsTable = new PluginsTable(this);
        setLayout(new TableLayout(
                new double[]{separatorGap, TableLayout.FILL, verticalGap, TableLayout.PREFERRED, separatorGap},
                new double[]{verticalGap, TableLayout.PREFERRED, verticalGap, TableLayout.FILL, separatorGap,
                        TableLayout.PREFERRED, verticalGap}
        ));
        add(getTopPanel(), "1, 1");
        add(getLegendPanel(), "3, 1");
        add(new JScrollPane(pluginsTable), "1, 3, 3, 3");
        add(getBottomPanel(), "1, 5, 3, 5");

        File upload = new File(uploadDirectoryPath);
        File download = new File(downloadDirectoryPath);
        if (!upload.exists())
            upload.mkdirs();
        if (!download.exists())
            download.mkdirs();
        updateDirectory.setText(upload.getAbsolutePath());
        downloadDirectory.setText(download.getAbsolutePath());
        updateFolder = upload;
        downloadFolder = download;
    }

    private void resetState() {
        uploadToServer.setEnabled(false);
        downloadFromServer.setEnabled(false);
        delete.setEnabled(false);
    }

    private void setListeners() {
        pluginsTable.getDefaultEditor(String.class).addCellEditorListener(new CellEditorListener() {
            @Override
            public void editingStopped(ChangeEvent changeEvent) {
                int vRow = pluginsTable.getSelectedRow();
                if (vRow == -1) //if no row selected
                    return;
                System.out.println("vRow = " + vRow);
                System.out.println(changeEvent.hashCode());
                String description = (String) ((TableCellEditor) changeEvent.getSource()).getCellEditorValue();
                System.out.println("current thread: " + Thread.currentThread().getName());
                String pluginName = (String) pluginsTable.getValueAt(vRow, 0);
                PluginState plugin = pluginsStates.getPluginsStates().get(pluginName);
                plugin.setDescription(description);

                // Update plugins description on server if it's necessary
                if (plugin.isAvailableOnServer())
                    Controller.adjustPlugin(plugin.getAlias(), description, null, plugin.getPluginSide());
                pluginsTable.update();
            }

            @Override
            public void editingCanceled(ChangeEvent changeEvent) {
                //do nothing
            }
        });

        pluginsTable.addSelectionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                int selectedRow = pluginsTable.getSelectedRow();
                if (selectedRow == -1)
                    return;
                String pluginName = (String) pluginsTable.getModel().getValueAt(
                        pluginsTable.convertRowIndexToModel(selectedRow), 0);
                PluginState plugin = pluginsStates.getPluginsStates().get(pluginName);
                uploadToServer.setEnabled(plugin.isAvailableInUpdates());
                downloadFromServer.setEnabled(plugin.isAvailableOnServer());
                delete.setEnabled(true);
            }
        });

        refresh.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                updatePluginsStates();
            }
        });

        chooseDownloadDirectory.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                JDirectoryChooser directoryChooser = new JDirectoryChooser();
                int returnVal = directoryChooser.showDialog(PluginsManagementPluginV2.this, "Выбрать");
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    updateDownloadDirectory(directoryChooser.getSelectedFile());
                    downloadDirectoryPath = directoryChooser.getSelectedFile().getAbsolutePath();
                }
            }
        });

        downloadDirectory.registerKeyboardAction(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                File directory = new File(downloadDirectory.getText());
                if (!directory.exists() || !directory.isDirectory()) {
                    JOptionPane.showMessageDialog(PluginsManagementPluginV2.this, "Такой директории не существует",
                            "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                updateDownloadDirectory(directory);
                downloadDirectoryPath = downloadDirectory.getText();
            }
        }, KeyStroke.getKeyStroke(VK_ENTER, 0, false), WHEN_FOCUSED);

        downloadDirectory.registerKeyboardAction(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                downloadDirectory.setText(downloadDirectoryPath);
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), WHEN_FOCUSED);

        chooseUploadDirectory.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                JDirectoryChooser directoryChooser = new JDirectoryChooser();
                int returnVal = directoryChooser.showDialog(PluginsManagementPluginV2.this, "Выбрать");
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    updateUploadDirectory(directoryChooser.getSelectedFile());
                    uploadDirectoryPath = directoryChooser.getSelectedFile().getAbsolutePath();
                }
            }
        });

        updateDirectory.registerKeyboardAction(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                File directory = new File(updateDirectory.getText());
                if (!directory.exists() || !directory.isDirectory()) {
                    JOptionPane.showMessageDialog(PluginsManagementPluginV2.this, "Такой директории не существует",
                            "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                updateUploadDirectory(directory);
                uploadDirectoryPath = updateDirectory.getText();
            }
        }, KeyStroke.getKeyStroke(VK_ENTER, 0, false), WHEN_FOCUSED);

        updateDirectory.registerKeyboardAction(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                updateDirectory.setText(uploadDirectoryPath);
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), WHEN_FOCUSED);

        delete.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                if (pluginsTable.getSelectedRow() == -1)
                    return;
                if (JOptionPane.showConfirmDialog(
                        PluginsManagementPluginV2.this,
                        "Вы действительно хотите удалить плагин?",
                        "Удаление плагина",
                        JOptionPane.YES_NO_OPTION
                ) == JOptionPane.NO_OPTION) return;
                String pluginName = (String) pluginsTable.getModel().getValueAt(
                        pluginsTable.convertRowIndexToModel(pluginsTable.getSelectedRow()), 0);
                PluginState plugin = pluginsStates.getPluginsStates().get(pluginName);

                // Delete from server
                if (plugin.isAvailableOnServer())
                    if (plugin.getPluginSide() == PluginSide.Server)
                        Controller.removeServerPlugin(pluginName);
                    else
                        Controller.removeClientPlugin(pluginName);


                // Delete from updates
                if (plugin.isAvailableInUpdates()) {
                    String[] possibleExtensions = {".php", ".jar"};
                    for (String extension : possibleExtensions) {
                        File pluginFile = new File(updateFolder.getAbsolutePath(), pluginName + extension);
                        if (pluginFile.exists()) {
                            pluginFile.delete();
                            break;
                        }
                    }
                }

                // Delete from downloads
                if (plugin.isAvailableInDownloads()) {
                    String[] possibleExtensions = {".php", ".jar"};
                    for (String extension : possibleExtensions) {
                        File pluginFile = new File(downloadFolder.getAbsolutePath(), pluginName + extension);
                        if (pluginFile.exists()) {
                            pluginFile.delete();
                            break;
                        }
                    }
                }

                pluginsStates.getPluginsStates().remove(pluginName);
                pluginsTable.update();
            }
        });

        downloadFromServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                final String pluginName = (String) pluginsTable.getModel().getValueAt(
                        pluginsTable.convertRowIndexToModel(pluginsTable.getSelectedRow()), 0);
                ResponseHandler<DownloadPluginResponse> handler = new ResponseHandler<DownloadPluginResponse>() {
                    @Override
                    public void success(DownloadPluginResponse response) {
                        byte[] pluginData = response.pluginBytes;

                        String fileExtension;
                        if (pluginsStates.getPluginsStates().get(pluginName).getPluginSide() == PluginSide.Server)
                            fileExtension = ".php";
                        else
                            fileExtension = ".jar";
                        File downloadedPlugin = new File(downloadFolder.getAbsolutePath(), pluginName + fileExtension);
                        try {
                            if (downloadedPlugin.exists())
                                downloadedPlugin.delete();
                            downloadedPlugin.createNewFile();
                            if (pluginData != null) {
                                FileOutputStream fos = new FileOutputStream(downloadedPlugin);
                                fos.write(pluginData);
                                fos.close();
                            }
                            pluginsStates.getPluginsStates().get(pluginName).setAvailableInDownloads(true);
                            pluginsTable.update();
                            if (pluginData == null)
                                JOptionPane.showMessageDialog(PluginsManagementPluginV2.this, "Плагин не содержит данных", "",
                                        JOptionPane.ERROR_MESSAGE);
                            else
                                JOptionPane.showMessageDialog(PluginsManagementPluginV2.this, "Плагин успешно скачан", "",
                                        JOptionPane.INFORMATION_MESSAGE);
                        } catch (FileNotFoundException ignore) {
                        } catch (IOException ignore) {
                        }
                    }

                    @Override
                    public void fail(ServerFailReason exception) {
                    }
                };
                Controller.downloadPlugin(pluginName, handler);
            }
        });

        uploadToServer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                String pluginName = (String) pluginsTable.getModel().getValueAt(
                        pluginsTable.convertRowIndexToModel(pluginsTable.getSelectedRow()), 0);
                PluginState plugin = pluginsStates.getPluginsStates().get(pluginName);

                String[] possibleExtensions = {".php", ".jar"};
                File pluginFile = null;
                String pluginExtension = null;
                for (String extension : possibleExtensions) {
                    pluginFile = new File(updateFolder.getAbsolutePath(), pluginName + extension);
                    if (pluginFile.exists()) {
                        pluginExtension = extension;
                        break;
                    }
                }

                PluginSide side = null;
                if (pluginExtension != null) {
                    if (pluginExtension.equals(".php"))
                        side = PluginSide.Server;
                    else
                        side = PluginSide.Client;
                }
                Controller.adjustPlugin(pluginName, plugin.getDescription(), pluginFile, side);


                File backup = null;
                if (pluginFile != null)
                    backup = new File(pluginFile.getAbsolutePath() + ".uploaded");
                try {
                    if (backup != null) {
                        if (backup.exists())
                            backup.delete();
                        backup.createNewFile();
                    }
                } catch (IOException ignored) {
                }
                FileSystemUtils.copyFile(pluginFile, backup);

                File toDownloads = null;
                if (pluginFile != null)
                    toDownloads = new File(downloadFolder.getAbsolutePath(), pluginName + pluginExtension);
                FileSystemUtils.copyFile(pluginFile, toDownloads);

                if (pluginFile != null) {
                    pluginFile.delete();
                }

                plugin.setAvailableInUpdates(false);
                plugin.setAvailableOnServer(true);
                plugin.setAvailableInDownloads(true);

                pluginsTable.update();
                JOptionPane.showMessageDialog(PluginsManagementPluginV2.this, "Плагин на сервере обновлен", "",
                        JOptionPane.INFORMATION_MESSAGE);
            }
        });
    }

    private void updateDownloadDirectory(File folder) {
        // Remove plugins from old update directory
        for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet())
            if (entry.getValue().isAvailableInDownloads() && !entry.getValue().isAvailableInUpdates() &&
                    !entry.getValue().isAvailableOnServer())
                pluginsStates.getPluginsStates().remove(entry.getKey());

        downloadFolder = folder;
        downloadDirectory.setText(downloadFolder.getAbsolutePath());
        updatePluginsStates();
    }

    private void updateUploadDirectory(File folder) {
        // Remove plugins from old download directory
        for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet())
            if (entry.getValue().isAvailableInUpdates() && !entry.getValue().isAvailableInDownloads() &&
                    !entry.getValue().isAvailableOnServer())
                pluginsStates.getPluginsStates().remove(entry.getKey());

        updateFolder = folder;
        updateDirectory.setText(updateFolder.getAbsolutePath());
        updatePluginsStates();
    }

    private JPanel getTopPanel() {
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new TableLayout(
                new double[]{TableLayout.FILL, separatorGap, TableLayout.PREFERRED},
                new double[]{TableLayout.PREFERRED, TableLayout.PREFERRED, separatorGap, TableLayout.PREFERRED,
                        TableLayout.PREFERRED}
        ));
        topPanel.add(chooseDownloadDirectory, "2, 1");
        topPanel.add(chooseUploadDirectory, "2, 4");
        topPanel.add(downloadDirectory, "0, 1");
        topPanel.add(updateDirectory, "0, 4");
        topPanel.add(new JLabel("Каталог для сохраненных плагинов"), "0, 0");
        topPanel.add(new JLabel("Каталог с обновлениями"), "0, 3");
        return topPanel;
    }

    private JPanel getBottomPanel() {
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new TableLayout(
                new double[]{TableLayout.PREFERRED, TableLayout.FILL, TableLayout.PREFERRED, separatorGap,
                        TableLayout.PREFERRED, separatorGap, TableLayout.PREFERRED},
                new double[]{TableLayout.PREFERRED}
        ));

        bottomPanel.add(refresh, "0, 0");
        bottomPanel.add(downloadFromServer, "2, 0");
        bottomPanel.add(uploadToServer, "4, 0");
        bottomPanel.add(delete, "6, 0");
        return bottomPanel;
    }

    private JPanel getLegendPanel() {
        JPanel legendPanel = new JPanel();
        legendPanel.setLayout(new TableLayout(
                new double[]{TableLayout.PREFERRED, separatorGap, TableLayout.PREFERRED},
                new double[]{TableLayout.PREFERRED, separatorGap, TableLayout.PREFERRED, separatorGap, TableLayout.PREFERRED}
        ));
        legendPanel.add(new JLabel(ImageResources.SERVER_IMAGE), "0, 0");
        legendPanel.add(new JLabel("Плагин доступен на сервере"), "2, 0");
        legendPanel.add(new JLabel(ImageResources.UPLOAD_IMAGE), "0, 2");
        legendPanel.add(new JLabel("Плагин доступен среди обновлений"), "2, 2");
        legendPanel.add(new JLabel(ImageResources.DOWNLOAD_IMAGE), "0, 4");
        legendPanel.add(new JLabel("Плагин загружен с сервера"), "2, 4");
        return legendPanel;
    }

    private void updatePluginsOnServer(PluginSide pluginSide, AvailablePluginsResponse response) {
        // Update available plugins on server
        for (int i = 0; i < response.aliases.length; i++)
            if (pluginsStates.getPluginsStates().containsKey(response.aliases[i])) {

                PluginState pluginState = pluginsStates.getPluginsStates().get(response.aliases[i]);
                pluginState.setDescription(response.descriptions[i]);
                pluginState.setAvailableOnServer(true);
                pluginState.setPluginSide(pluginSide);

                pluginsOnServer.add(pluginState.getAlias());
            } else {
                PluginState pluginState = new PluginState();
                pluginState.setAvailableOnServer(true);
                pluginState.setAlias(response.aliases[i]);
                pluginState.setDescription(response.descriptions[i]);
                pluginState.setPluginSide(pluginSide);
                pluginsStates.getPluginsStates().put(response.aliases[i], pluginState);

                pluginsOnServer.add(pluginState.getAlias());
            }
        // Set PluginState.availableOnServer to false if it's necessary
        for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet()) {
            boolean isPluginOnServer = false;
            for (String pluginOnServer : pluginsOnServer)
                if (entry.getKey().equals(pluginOnServer))
                    isPluginOnServer = true;

            if (!isPluginOnServer)
                entry.getValue().setAvailableOnServer(false);
        }
    }

    private void updateLocalPlugins() {
        // Update available plugins in updates
        List<String> pluginsInUpdate = new ArrayList<String>();
        if (updateFolder != null) {
            String[] files = updateFolder.list(new FilenameFilter() {
                @Override
                public boolean accept(File file, String name) {
                    return name.endsWith(".php") || name.endsWith(".jar");
                }
            });

            for (String pluginFile : files) {
                PluginSide pluginSide;
                String plugin;
                if (pluginFile.endsWith(".php")) {
                    pluginSide = PluginSide.Server;
                    plugin = pluginFile.substring(0, pluginFile.lastIndexOf(".php"));
                } else {
                    pluginSide = PluginSide.Client;
                    plugin = pluginFile.substring(0, pluginFile.lastIndexOf(".jar"));
                }

                if (pluginsStates.getPluginsStates().containsKey(plugin)) {
                    pluginsStates.getPluginsStates().get(plugin).setAvailableInUpdates(true);
                    pluginsInUpdate.add(plugin);
                } else {
                    PluginState pluginState = new PluginState();
                    pluginState.setAvailableInUpdates(true);
                    pluginState.setAlias(plugin);
                    pluginState.setPluginSide(pluginSide);
                    pluginsStates.getPluginsStates().put(plugin, pluginState);
                    pluginsInUpdate.add(plugin);
                }

            }
            // Set PluginState.availableInUpdates to false if it's necessary
            for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet()) {
                boolean isPluginInUpdate = false;
                for (String pluginInUpdate : pluginsInUpdate)
                    if (entry.getKey().equals(pluginInUpdate))
                        isPluginInUpdate = true;

                if (!isPluginInUpdate)
                    entry.getValue().setAvailableInUpdates(false);
            }
        } else
            for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet())
                entry.getValue().setAvailableInUpdates(false);

        //TODO remove code duplication

        // Update available plugins in downloads
        List<String> pluginsInDownload = new ArrayList<String>();
        if (downloadFolder != null) {
            String[] files = downloadFolder.list(new FilenameFilter() {
                @Override
                public boolean accept(File file, String name) {
                    return name.endsWith(".php") || name.endsWith(".jar");
                }
            });

            for (String pluginFile : files) {
                PluginSide pluginSide;
                String plugin;
                if (pluginFile.endsWith(".php")) {
                    pluginSide = PluginSide.Server;
                    plugin = pluginFile.substring(0, pluginFile.lastIndexOf(".php"));
                } else {
                    pluginSide = PluginSide.Client;
                    plugin = pluginFile.substring(0, pluginFile.lastIndexOf(".jar"));
                }

                if (pluginsStates.getPluginsStates().containsKey(plugin)) {
                    pluginsStates.getPluginsStates().get(plugin).setAvailableInDownloads(true);
                    pluginsInDownload.add(plugin);
                } else {
                    PluginState pluginState = new PluginState();
                    pluginState.setAvailableInDownloads(true);
                    pluginState.setAlias(plugin);
                    pluginState.setPluginSide(pluginSide);
                    pluginsStates.getPluginsStates().put(plugin, pluginState);
                    pluginsInDownload.add(plugin);
                }


                // Set PluginState.availableInUpdates to false if it's necessary
                for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet()) {
                    boolean isPluginInDownload = false;
                    for (String pluginInDownload : pluginsInDownload)
                        if (entry.getKey().equals(pluginInDownload))
                            isPluginInDownload = true;

                    if (!isPluginInDownload)
                        entry.getValue().setAvailableInDownloads(false);
                }
            }
        } else
            for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet())
                entry.getValue().setAvailableInDownloads(false);

        // Remove nonexistent plugins
        for (Map.Entry<String, PluginState> entry : pluginsStates.getPluginsStates().entrySet()) {
            boolean exist = false;
            String pluginName = entry.getValue().getAlias();
            for (String serverPlugin : pluginsOnServer)
                if (serverPlugin.equals(pluginName)) {
                    exist = true;
                    break;
                }

            if (!exist)
                for (String updatePlugin : pluginsInUpdate)
                    if (updatePlugin.equals(pluginName)) {
                        exist = true;
                        break;
                    }

            if (!exist)
                for (String downloadPlugin : pluginsInDownload)
                    if (downloadPlugin.equals(pluginName)) {
                        exist = true;
                        break;
                    }

            if (!exist)
                pluginsStates.getPluginsStates().remove(pluginName);
        }
    }

    public void updatePluginsStates() {
        refresh.setEnabled(false);
        ResponseHandler<AvailablePluginsResponse> handler = new ResponseHandler<AvailablePluginsResponse>() {
            @Override
            public void success(AvailablePluginsResponse response) {
                updatePluginsOnServer(PluginSide.Client, response);
                updateLocalPlugins();
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pluginsTable.update();
                        refresh.setEnabled(true);
                    }
                });
            }

            @Override
            public void fail(ServerFailReason exception) {
                refresh.setEnabled(true);
            }
        };
        Controller.getAvailableClientPlugins(handler);
        Controller.getAvailableServerPlugins(handler);
    }


    public class PluginsStates {

        private Map<String, PluginState> pluginsStates = new ConcurrentHashMap<String, PluginState>();

        public Map<String, PluginState> getPluginsStates() {
            return pluginsStates;
        }
    }
}
